import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_chat/common/enum/enums.dart';
import 'package:flutter_chat/common/service/retry_service.dart';
import 'package:flutter_chat/common/store/stores.dart';
import 'package:flutter_chat/common/utils/utils.dart';
import 'package:get/get.dart';
import 'package:jiffy/jiffy.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

class WebSocketService extends GetxService {
  /// 单例
  static WebSocketService get to => Get.find();

  /// 连接地址
  final String _wsUrl = 'ws://192.168.108.124:8181/websocket';

  /// 状态
  final _status = SocketStatus.closed.obs;
  set status(SocketStatus value) => _status.value = value;
  SocketStatus get status => _status.value;

  /// WebSocket
  WebSocketChannel? _channel;

  /// WebSocket监听器列表
  final ObserverList<Function> _webSocketListeners = ObserverList<Function>();

  /// 心跳重试KEY
  final String _heartBeatKey = "heart_beat";

  /// 心跳间隔(毫秒)
  final int _heartTime = 5000;

  /// 重连KEY
  final String _reconnectKey = "reconnect";

  /// 重连的次数
  final int _reconnectCount = 60;

  /// 重连计数器
  int _reconnectNumber = 0;

  /// 初始化
  void initWebSocket({
    Function()? callback,
  }) {
    open(callback: callback);
  }

  /// 打开连接
  void open({Function()? callback}) async {
    if (status == SocketStatus.connected) {
      LogUtil.p('websocket ------- 连接已打开 -------');
      return;
    }
    try {
      _channel = IOWebSocketChannel.connect(
        _wsUrl,
        connectTimeout: const Duration(seconds: 10),
        headers: {
          "token": UserStore.to.token,
        },
      );
      _channel?.ready.then((value) {
        if (status == SocketStatus.closed) {
          LogUtil.p('websocket ------- 连接成功 -------');
          status = SocketStatus.connected;
          startHeartBeat();
          if (callback != null) {
            callback.call();
          }
        }
      });
      _channel?.stream.listen(
        receptionMessage,
        onError: _onError,
        onDone: _onDone,
      );
    } on DioException catch (e) {
      _onError(e);
    } catch (e) {
      _onError(e);
    }
  }

  /// 关闭连接
  void closed() {
    if (_channel != null) {
      _channel!.sink.close();
      _channel = null;
    }
  }

  /// 接收消息
  /// 也可以使用此方法给所有订阅者发送消息
  void receptionMessage(message) {
    // 将消息循环发送给订阅者
    for (var callback in _webSocketListeners) {
      callback(message);
    }
  }

  /// 连接出错
  void _onError(error) {
    LogUtil.p('websocket ------- 连接出错：$error -------');
  }

  /// 连接关闭
  void _onDone() {
    LogUtil.p('websocket ------- 连接关闭 -------');
    status = SocketStatus.closed;
    closed();
    startReconnect();
  }

  ///  加入订阅者
  addListener(Function callback) {
    _webSocketListeners.add(callback);
  }

  ///  删除订阅者
  removeListener(Function callback) {
    _webSocketListeners.remove(callback);
  }

  ///  删除所有订阅者
  removeAllListener() {
    try {
      for (int i = 0; i < _webSocketListeners.length; i++) {
        removeListener(_webSocketListeners.elementAt(i));
      }
    } catch (e) {
      LogUtil.p('删除所有订阅者出错: $e');
    }
  }

  /// 发送消息给服务端
  void sendMessage(String message) {
    if (_channel != null) {
      switch (status) {
        case SocketStatus.connected:
          _channel?.sink.add(message);
          break;
        case SocketStatus.closed:
          LogUtil.p('websocket连接已关闭，发送失败: $message');
          closeHeartBeat();
          break;
        default:
          closeHeartBeat();
          break;
      }
    } else {
      LogUtil.p('websocket连接未打开，发送失败: $message');
      closeHeartBeat();
    }
  }

  /// 启动心跳定时器
  void startHeartBeat() {
    RetryService.to.startService(
      _heartBeatKey,
      () async {
        LogUtil.p("发送心跳消息 ${Jiffy.now().Hms}");
        sendMessage("心跳消息 ${Jiffy.now().Hms}");
        return false;
      },
      interval: Duration(milliseconds: _heartTime),
    );
  }

  /// 关闭心跳定时器
  void closeHeartBeat() {
    RetryService.to.stopService(_heartBeatKey);
  }

  /// 开始重连
  void startReconnect() {
    RetryService.to.startService(
      _reconnectKey,
      () async {
        if (_reconnectNumber < _reconnectCount) {
          _reconnectNumber++;
          LogUtil.p('websocket正在进行第$_reconnectNumber次重连，时间：${Jiffy.now().Hms}');
          open(callback: () {
            closeReconnect();
          });
        } else {
          LogUtil.p('停止重连：重连次数超过最大次数，时间：${Jiffy.now().Hms}');
          closeReconnect();
        }
        return false;
      },
      interval: Duration(milliseconds: _heartTime),
    );
  }

  /// 关闭重连
  void closeReconnect() {
    RetryService.to.stopService(_reconnectKey);
    _reconnectNumber = 0;
  }

  /// 关闭连接并停止重连
  void closeAndStopReconnect() {
    closed();
    Future.delayed(const Duration(seconds: 1), () {
      closeReconnect();
    });
  }
}
